package com.dji.compose_learning.sample

import android.util.Log
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import org.junit.After
import org.junit.Before
import org.junit.Test
import kotlin.coroutines.EmptyCoroutineContext

class KotlinDelegateSampleTest {

    @Before
    fun setUp() {
    }

    @After
    fun tearDown() {
    }

    @Test
    fun testSample() {
//        val test = KotlinDelegateSample()
//        test.testSample()

        //part1
//        val person = Person3()
//        println(person.name)
//        println(person.sex)
//        person.name = ""
//        person.sex = "woman"
//        println(person.name)
//        println(person.sex)

        //part2
//        val person = Person4()
//        person.name = "Tom"
//        person.sex = "男"
//        person.grade = 2
//        person.age = 14
//        println("${person.name},${person.sex},${person.age},${person.grade},${person.educationInfo}")
//        person.name = "James"
//        person.sex = "女"
//        person.age = 23
//        person.grade = 8
//        println("${person.name},${person.sex},${person.age},${person.grade},${person.educationInfo}")

        //part3
//        val person = Person5()
//        println(person.name)

        //part4
//        val myOperation = MyOperation(CommonOperation())
//        myOperation.add()
//        myOperation.delete()
//        myOperation.query()
//        myOperation.update()
//        val myOperation1 = MyOperation1()
//        myOperation1.add()
//        myOperation1.delete()
//        myOperation1.query()
//        myOperation1.update()

        //part5
        val test = KotlinDelegateSample()
        test.fu()
    }

    fun print(msg: String) {
        Log.i("buobao", msg)
    }

    @Test
    fun testSample1() {
        runBlocking {
            val job = GlobalScope.launch {
                withContext(CoroutineName("subsub") + Dispatchers.IO) {
                    co1()
                }
                async { }
//                async { co1() }
                co2()

                val num1 = async {
                    delay(200)
                    10
                }
                val num2 = async {
                    delay(300)
                    20
                }
                print((num1.await() + num2.await()).toString())
            }
            val job2 = GlobalScope.launch {
                co3()
            }
            joinAll(job, job2)
        }
    }

    suspend fun co1() = runBlocking {
        delay(1000)
        print("co1")
    }

    fun co2() = print("co2")

    suspend fun co3() = runBlocking {
        delay(1100)
        print("co3")
    }

    @Test
    fun testSample2() = runBlocking {
        //两个协程之间会有并发
        //在一个协程内部可以指定部分代码在不同的线程中执行（使用withcontext），但是协程内部仍然是顺序执行的
        //要在一个协程内部实现并发需要通过async
        val job1 = CoroutineScope(
            EmptyCoroutineContext + CoroutineName("buobao-test-1") + SupervisorJob()
        )
            .launch {
                for (i in 0 until 10) {
                    println("${coroutineContext[CoroutineName]}:$i")
                    delay(100)
                }
            }

        val job2 = CoroutineScope(
            EmptyCoroutineContext + CoroutineName("buobao-test-2") + SupervisorJob()
        )
            .launch(start = CoroutineStart.LAZY) {
                for (i in 0 until 10) {
                    println("${coroutineContext[CoroutineName]}:$i")
                    delay(80)
                }
            }
        job2.start()
        joinAll(job1, job2)
    }


    @Test
    fun testFlow() = runBlocking {
        // sample 1,定义一个冷流
        val intFlow = flow {
            (1..9).forEach {
                emit(it)
                if (it == 5) {
                    throw NullPointerException("this is a exception message.")
                }
            }
        }
        //当这个冷流被消费的时候它才会被执行
        MainScope().launch {
            intFlow.flowOn(Dispatchers.IO)
                .catch {
                    //异常处理
                    println(it.message)
                }
                .onCompletion {
                    println("receive:${it?.message}")
                }
                .collect {
                    println(it)
                }
        }.join()

        // sample 2
        val stringFlow = flow {
            listOf("Compose", "Java", "Jetpack", "NBA").forEach {
                emit(it)
                delay(200)
            }
        }.onEach { println(it) } //这里onEach把下游观察需要做的事情定义好了

        //第一种调用方式
        val job1 = MainScope().launch {
            stringFlow.collect()
        }
        //第二种调用方式
        val job2 = stringFlow.launchIn(MainScope())

        joinAll(job1, job2)
    }

    @Test
    fun testSample3() = runBlocking {
        val channel = Channel<Int>()
        //启动一个协程发射数据
        launch {
            repeat(10) {
                delay(1000)
                channel.send(it)
            }
            channel.close() //发送完需要关闭，否则下游通过迭代获取值会导致协程一直获取数据
        }

        //当前协程获取数据
        repeat(2) {
            println("receive:${channel.receive()}")
        }
        //或者
        var receiveCount = 0
        val iterator = channel.iterator()
        while (iterator.hasNext()) {
            val next = iterator.next()
            println("iterator receive:${next}")
            receiveCount++
            if(receiveCount > 3) break
        }
        //或者
        for (item in channel) {
            println("for receive:$item")
        }
    }
}






















